﻿using Sidvall.CodeGenerator.Security;
using System.Collections.Generic;
using System.Linq;

namespace Sidvall.CodeGenerator
{
    public class DomainObject
    {
        #region Public Members

        public const string DefaultKeySeparator = "|*.";

        public string Tag { get; set; }
        public string Namespace { get; set; }
        public string NamespaceInDataStore { get; set; }
        public string Name { get; set; }
        public string NameInDataStore { get; set; }
        public bool? IsReadOnly { get; set; }
        public DomainObjectIndexCollection Indexes { get; private set; }
        public DomainModel DomainModel { get; internal set; }
        public bool IsDatabaseOnly { get; set; }
        public bool HasSqliteDataLayer { get; set; }
        public bool HasUILayer { get; set; }
        public bool HasWebLayer { get; set; }
        public bool HasWebApiLayer { get; set; }
        public OperationTypes WebApiOperationTypes { get; set; }

        #region Properties

        private DomainObjectPropertyCollection _FilteredProperties;
        private DomainObjectPropertyCollection _Properties;
        public DomainObjectPropertyCollection Properties
        {
            get
            {
                if ((this.DomainModel != null) && (this.DomainModel.DomainModelFilter != null))
                {
                    if (_FilteredProperties == null)
                    {
                        _FilteredProperties = new DomainObjectPropertyCollection();
                        foreach (var item in _Properties)
                        {
                            if (this.DomainModel.DomainModelFilter.IncludedDomainObjectProperties.Contains(item.FullName))
                            {
                                _FilteredProperties.Add(item);
                                continue;
                            }
                            if (this.DomainModel.DomainModelFilter.ExcludedDomainObjectProperties.Contains(item.FullName))
                                continue;
                            if ((this.DomainModel.DomainModelFilter.ExcludePropertiesWithParentRelations) && (item.ParentRelations.Count > 0))
                                continue;
                            _FilteredProperties.Add(item);
                        }
                    }
                    return _FilteredProperties;
                }
                return _Properties;
            }
            private set
            {
                _Properties = value;
            }
        }

        #endregion
        #region DatabaseRelations

        private DomainObjectRelationCollection _FilteredDatabaseRelations;
        private DomainObjectRelationCollection _DatabaseRelations;
        public DomainObjectRelationCollection DatabaseRelations
        {
            get
            {
                if ((this.DomainModel != null) && (this.DomainModel.DomainModelFilter != null))
                {
                    if (_FilteredDatabaseRelations == null)
                    {
                        _FilteredDatabaseRelations = new DomainObjectRelationCollection();
                        foreach (var item in _DatabaseRelations)
                        {
                            if (this.DomainModel.DomainModelFilter.IncludedDomainObjectProperties.Contains(item.FullName))
                            {
                                _FilteredDatabaseRelations.Add(item);
                                continue;
                            }
                            if (this.DomainModel.DomainModelFilter.ExcludedDomainObjectProperties.Contains(item.FullName))
                                continue;
                            _FilteredDatabaseRelations.Add(item);
                        }
                    }
                    return _FilteredDatabaseRelations;
                }
                return _DatabaseRelations;
            }
            private set
            {
                _DatabaseRelations = value;
                this.Relations = null;
            }
        }

        #endregion
        #region IsReadOnlyResolved

        public bool IsReadOnlyResolved
        {
            get
            {
                if (this.IsReadOnly != null)
                    return this.IsReadOnly.Value;
                return false;
            }
        }

        #endregion
        #region Keys

        private DomainObjectPropertyCollection _Keys;
        public DomainObjectPropertyCollection Keys
        {
            get
            {
                if (_Keys == null)
                {
                    _Keys = new DomainObjectPropertyCollection();
                    foreach (var item in this.Properties)
                    {
                        if (item.IsKeyResolved)
                            _Keys.Add(item);
                    }
                }
                return _Keys;
            }
            private set
            {
                _Keys = value;
            }
        }

        #endregion
        #region KeySeparator

        private string _KeySeparator;
        public string KeySeparator
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_KeySeparator))
                    return DefaultKeySeparator;
                return _KeySeparator;
            }
            set
            {
                _KeySeparator = value;
            }
        }

        #endregion
        #region ManyRelations

        private DomainObjectRelationCollection _ManyRelations;
        public DomainObjectRelationCollection ManyRelations
        {
            get
            {
                if (_ManyRelations == null)
                {
                    _ManyRelations = new DomainObjectRelationCollection();
                    foreach (var item in this.Relations)
                    {
                        if (item.RelatedObjectMultiplicity == Multiplicity.Many)
                            _ManyRelations.Add(item);
                    }
                }
                return _ManyRelations;
            }
            private set
            {
                _ManyRelations = value;
            }
        }

        #endregion
        #region Relations

        private DomainObjectRelationCollection _Relations;
        public DomainObjectRelationCollection Relations
        {
            get
            {
                if (_Relations == null)
                {
                    _Relations = new DomainObjectRelationCollection();
                    foreach (var item in this.DatabaseRelations)
                    {
                        if (!item.IsDatabaseOnly)
                            _Relations.Add(item);
                    }
                }
                return _Relations;
            }
            private set
            {
                _Relations = value;
                this.ManyRelations = null;
                this.ChildRelations = null;
                this.ParentRelations = null;
            }
        }

        #endregion
        #region ChildRelations

        private DomainObjectRelationCollection _ChildRelations;
        public DomainObjectRelationCollection ChildRelations
        {
            get
            {
                if (_ChildRelations == null)
                {
                    _ChildRelations = new DomainObjectRelationCollection();
                    foreach (var item in this.Relations)
                    {
                        if (item.RelationType == RelationType.ParentChild)
                            _ChildRelations.Add(item);
                    }
                }
                return _ChildRelations;
            }
            private set
            {
                _ChildRelations = value;
                this.ChildRelationsWithOneField = null;
                this.ParentAndChildRelations = null;
            }
        }

        #endregion
        #region ChildRelationsWithOneField

        private DomainObjectRelationCollection _ChildRelationsWithOneField;
        public DomainObjectRelationCollection ChildRelationsWithOneField
        {
            get
            {
                if (_ChildRelationsWithOneField == null)
                {
                    _ChildRelationsWithOneField = new DomainObjectRelationCollection();
                    foreach (var item in this.ChildRelations)
                    {
                        if (item.Fields.Count == 1)
                            _ChildRelationsWithOneField.Add(item);
                    }
                }
                return _ChildRelationsWithOneField;
            }
            private set
            {
                _ChildRelationsWithOneField = value;
            }
        }

        #endregion
        #region ParentAndChildRelations

        private DomainObjectRelationCollection _ParentAndChildRelations;
        public DomainObjectRelationCollection ParentAndChildRelations
        {
            get
            {
                if (_ParentAndChildRelations == null)
                {
                    _ParentAndChildRelations = new DomainObjectRelationCollection();
                    foreach (var item in this.ChildRelations)
                        _ParentAndChildRelations.Add(item);
                    foreach (var item in this.ParentRelations)
                        _ParentAndChildRelations.Add(item);
                }
                return _ParentAndChildRelations;
            }
            private set
            {
                _ParentAndChildRelations = value;
            }
        }

        #endregion
        #region ParentAndChildRelationsWithOneField

        private DomainObjectRelationCollection _ParentAndChildRelationsWithOneField;
        public DomainObjectRelationCollection ParentAndChildRelationsWithOneField
        {
            get
            {
                if (_ParentAndChildRelationsWithOneField == null)
                {
                    _ParentAndChildRelationsWithOneField = new DomainObjectRelationCollection();
                    foreach (var item in this.ParentAndChildRelations)
                    {
                        if (item.Fields.Count == 1)
                            _ParentAndChildRelationsWithOneField.Add(item);
                    }
                }
                return _ParentAndChildRelationsWithOneField;
            }
            private set
            {
                _ParentAndChildRelationsWithOneField = value;
            }
        }

        #endregion
        #region ParentRelations

        private DomainObjectRelationCollection _ParentRelations;
        public DomainObjectRelationCollection ParentRelations
        {
            get
            {
                if (_ParentRelations == null)
                {
                    _ParentRelations = new DomainObjectRelationCollection();
                    foreach (var item in this.Relations)
                    {
                        if (item.RelationType == RelationType.ChildParent)
                            _ParentRelations.Add(item);
                    }
                }
                return _ParentRelations;
            }
            private set
            {
                _ParentRelations = value;
                this.ParentRelationsWithOneField = null;
                this.ParentAndChildRelations = null;
            }
        }

        #endregion
        #region ParentRelationsWithOneField

        private DomainObjectRelationCollection _ParentRelationsWithOneField;
        public DomainObjectRelationCollection ParentRelationsWithOneField
        {
            get
            {
                if (_ParentRelationsWithOneField == null)
                {
                    _ParentRelationsWithOneField = new DomainObjectRelationCollection();
                    foreach (var item in this.ParentRelations)
                    {
                        if (item.Fields.Count == 1)
                            _ParentRelationsWithOneField.Add(item);
                    }
                }
                return _ParentRelationsWithOneField;
            }
            private set
            {
                _ParentRelationsWithOneField = value;
            }
        }

        #endregion
        #region PluralName

        public string PluralName
        {
            get
            {
                return TypeMapper.GetPluralName(this.Name);
            }
        }

        #endregion
        #region PluralNameInDataStore

        public string PluralNameInDataStore
        {
            get
            {
                return TypeMapper.GetPluralName(this.NameInDataStore);
            }
        }

        #endregion
        #region GeneratedProperties

        private DomainObjectPropertyCollection _GeneratedProperties;
        public DomainObjectPropertyCollection GeneratedProperties
        {
            get
            {
                if (_GeneratedProperties == null)
                {
                    _GeneratedProperties = new DomainObjectPropertyCollection();
                    foreach (var item in this.Properties)
                    {
                        if (item.IsGenerated)
                            _GeneratedProperties.Add(item);
                    }
                }
                return _GeneratedProperties;
            }
            private set
            {
                _GeneratedProperties = value;
            }
        }

        #endregion
        #region GeneratedKeyProperties

        private DomainObjectPropertyCollection _GeneratedKeyProperties;
        public DomainObjectPropertyCollection GeneratedKeyProperties
        {
            get
            {
                if (_GeneratedKeyProperties == null)
                {
                    _GeneratedKeyProperties = new DomainObjectPropertyCollection();
                    foreach (var item in this.GeneratedProperties)
                    {
                        if (item.IsKeyResolved)
                            _GeneratedKeyProperties.Add(item);
                    }
                }
                return _GeneratedKeyProperties;
            }
            private set
            {
                _GeneratedKeyProperties = value;
            }
        }

        #endregion
        #region GeneratedNonKeyProperties

        private DomainObjectPropertyCollection _GeneratedNonKeyProperties;
        public DomainObjectPropertyCollection GeneratedNonKeyProperties
        {
            get
            {
                if (_GeneratedNonKeyProperties == null)
                {
                    _GeneratedNonKeyProperties = new DomainObjectPropertyCollection();
                    foreach (var item in this.GeneratedProperties)
                    {
                        if (!item.IsKeyResolved)
                            _GeneratedNonKeyProperties.Add(item);
                    }
                }
                return _GeneratedNonKeyProperties;
            }
            private set
            {
                _GeneratedNonKeyProperties = value;
            }
        }

        #endregion
        #region ManualProperties

        private DomainObjectPropertyCollection _ManualProperties;
        public DomainObjectPropertyCollection ManualProperties
        {
            get
            {
                if (_ManualProperties == null)
                {
                    _ManualProperties = new DomainObjectPropertyCollection();
                    foreach (var item in this.Properties)
                    {
                        if (!item.IsGenerated)
                            _ManualProperties.Add(item);
                    }
                }
                return _ManualProperties;
            }
            private set
            {
                _ManualProperties = value;
            }
        }

        #endregion
        #region ManualKeyProperties

        private DomainObjectPropertyCollection _ManualKeyProperties;
        public DomainObjectPropertyCollection ManualKeyProperties
        {
            get
            {
                if (_ManualKeyProperties == null)
                {
                    _ManualKeyProperties = new DomainObjectPropertyCollection();
                    foreach (var item in this.ManualProperties)
                    {
                        if (item.IsKeyResolved)
                            _ManualKeyProperties.Add(item);
                    }
                }
                return _ManualKeyProperties;
            }
            private set
            {
                _ManualKeyProperties = value;
            }
        }

        #endregion
        #region ManualNonKeyProperties

        private DomainObjectPropertyCollection _ManualNonKeyProperties;
        public DomainObjectPropertyCollection ManualNonKeyProperties
        {
            get
            {
                if (_ManualNonKeyProperties == null)
                {
                    _ManualNonKeyProperties = new DomainObjectPropertyCollection();
                    foreach (var item in this.ManualProperties)
                    {
                        if (!item.IsKeyResolved)
                            _ManualNonKeyProperties.Add(item);
                    }
                }
                return _ManualNonKeyProperties;
            }
            private set
            {
                _ManualNonKeyProperties = value;
            }
        }

        #endregion
        #region RelationPaths

        private DomainObjectRelationPathCollection _RelationPaths;
        public DomainObjectRelationPathCollection RelationPaths
        {
            get
            {
                System.Collections.Generic.HashSet<string> names;
                System.Collections.Generic.List<DomainObjectRelationPath> items;

                if (_RelationPaths == null)
                {
                    _RelationPaths = new DomainObjectRelationPathCollection();
                    names = new System.Collections.Generic.HashSet<string>();
                    items = PrepareRelationPaths(_RelationPaths, names, this);
                    while (items.Count > 0)
                        items = PrepareRelationPaths(_RelationPaths, names, items);
                }
                return _RelationPaths;
            }
        }

        #endregion
        #region FullName

        public string FullName
        {
            get
            {
                return GetFullName(this.Namespace, this.Name);
            }
        }

        #endregion
        #region FullNameInDataStore

        public string FullNameInDataStore
        {
            get
            {
                return GetFullName(this.NamespaceInDataStore, this.NameInDataStore);
            }
        }

        #endregion
        #region TypeName

        public string TypeName
        {
            get
            {
                return this.Name.Replace(".", "_").Replace("-", "_");
            }
        }

        #endregion
        #region CollectionTypeName

        public string CollectionTypeName
        {
            get
            {
                if (this.DomainModel != null)
                    return string.Format(System.Globalization.CultureInfo.InvariantCulture, this.DomainModel.CollectionTypeNameFormat, this.TypeName);
                return string.Empty;
            }
        }

        #endregion

        #region AddDatabaseRelation

        public DomainObjectRelation AddDatabaseRelation(DomainObject relatedObject, Multiplicity sourceObjectMultiplicity, Multiplicity relatedObjectMultiplicity,
            string name, string sourceObjectPropertyName1, string relatedObjectPropertyName1, string sourceObjectPropertyName2, string relatedObjectPropertyName2,
            string sourceObjectPropertyName3, string relatedObjectPropertyName3, string sourceObjectPropertyName4, string relatedObjectPropertyName4)
        {
            return this.DatabaseRelations.Add(this, relatedObject, sourceObjectMultiplicity, relatedObjectMultiplicity, name, sourceObjectPropertyName1, relatedObjectPropertyName1,
                sourceObjectPropertyName2, relatedObjectPropertyName2, sourceObjectPropertyName3, relatedObjectPropertyName3, sourceObjectPropertyName4, relatedObjectPropertyName4);
        }

        #endregion
        #region AddIndex

        public DomainObjectIndex AddIndex(string indexName, bool isUnique, string propertyName1)
        {
            var item = new DomainObjectIndex()
            {
                NameInDataStore = indexName,
                IsUnique = isUnique
            };
            AddIndexField(item, propertyName1);
            this.Indexes.Add(item);
            return item;
        }

        public DomainObjectIndex AddIndex(string indexName, bool isUnique, string propertyName1, string propertyName2)
        {
            var item = AddIndex(indexName, isUnique, propertyName1);
            AddIndexField(item, propertyName2);
            return item;
        }

        public DomainObjectIndex AddIndex(string indexName, bool isUnique, string propertyName1, string propertyName2, string propertyName3)
        {
            var item = AddIndex(indexName, isUnique, propertyName1, propertyName2);
            AddIndexField(item, propertyName3);
            return item;
        }

        public DomainObjectIndex AddIndex(string indexName, bool isUnique, string propertyName1, string propertyName2, string propertyName3, string propertyName4)
        {
            var item = AddIndex(indexName, isUnique, propertyName1, propertyName2, propertyName3);
            AddIndexField(item, propertyName4);
            return item;
        }

        #endregion
        #region AddProperty

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "string")]
        public DomainObjectProperty AddProperty(string propertyName, bool isNullable, string defaultValue, int? maxLength, string stringFormat, string valueFormat, PropertyType type)
        {
            return AddProperty(propertyName, isNullable, defaultValue, maxLength, stringFormat, valueFormat, TypeMapper.GetTypeName(type), TypeMapper.IsValueType(type));
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "string")]
        public DomainObjectProperty AddProperty(string propertyName, bool isNullable, string defaultValue, int? maxLength, string stringFormat, string valueFormat, string typeName, bool isValueType)
        {
            var item = new DomainObjectProperty();
            item.Name = propertyName;
            item.IsValueType = isValueType;
            item.MaxLength = maxLength;
            item.TypeName = typeName;
            item.DefaultValue = defaultValue;
            item.StringFormat = stringFormat;
            item.ValueFormat = valueFormat;
            item.IsNullable = isNullable;
            this.Properties.Add(item);

            return item;
        }

        #endregion
        #region AddStringProperty

        public DomainObjectProperty AddStringProperty(string propertyName, string defaultValue, int? maxLength, string valueFormat)
        {
            return AddProperty(propertyName, false, defaultValue, maxLength, null, valueFormat, "string", false);
        }

        #endregion
        #region ClearCache

        public void ClearCache()
        {
            _FilteredProperties = null;
            _FilteredDatabaseRelations = null;
            if (_Properties != null)
                _Properties.ClearCache();
            this.Keys = null;
            this.Relations = null;
            this.ChildRelations = null;
            this.ChildRelationsWithOneField = null;
            this.ManyRelations = null;
            this.ParentAndChildRelations = null;
            this.ParentAndChildRelationsWithOneField = null;
            this.ParentRelations = null;
            this.ParentRelationsWithOneField = null;

            this.GeneratedKeyProperties = null;
            this.GeneratedNonKeyProperties = null;
            this.GeneratedProperties = null;
            this.ManualKeyProperties = null;
            this.ManualNonKeyProperties = null;
            this.ManualProperties = null;
        }

        #endregion
        #region GetProperty

        public DomainObjectProperty GetProperty(string propertyName)
        {
            return (from o in this.Properties
                    where o.Name.Equals(propertyName, System.StringComparison.OrdinalIgnoreCase)
                    select o).FirstOrDefault();
        }

        #endregion
        #region GetProperties

        public IEnumerable<DomainObjectProperty> GetProperties(PropertyType? propertyType, string typeName, bool? isGenerated, bool? isKey, bool? isNullable)
        {
            return (from o in this.Properties
                    where (propertyType == null || o.PropertyType == propertyType) && (string.IsNullOrWhiteSpace(typeName) || o.NotNullableTypeName == typeName) &&
                        (isGenerated == null || o.IsGenerated == isGenerated) && (isKey == null || o.IsKeyResolved == isKey) && (isNullable == null || o.IsNullableResolved == isNullable)
                    select o);
        }

        #endregion
        #region GetRelations

        public System.Collections.ObjectModel.Collection<DomainObjectRelation> GetRelations(string relatedDomainObjectName)
        {
            return this.Relations.FindByDomainObjectName(relatedDomainObjectName);
        }

        #endregion
        #region Import

        public void Import(DomainObject item)
        {
            if (item == null)
                return;

            if (item.Namespace != null)
                this.Namespace = item.Namespace;
            if (item.NamespaceInDataStore != null)
                this.NamespaceInDataStore = item.NamespaceInDataStore;
            if (item.Name != null)
                this.Name = item.Name;
            if (item.NameInDataStore != null)
                this.NameInDataStore = item.NameInDataStore;
            if (item.IsReadOnly != null)
                this.IsReadOnly = item.IsReadOnly;
            this.Properties.Import(item.Properties);
            this.DatabaseRelations.Import(item.DatabaseRelations);
            this.Indexes.Import(item.Indexes);
        }

        #endregion
        #region RemoveRelationsByDomainObjectNames

        public void RemoveRelationsByDomainObjectNames(bool isDatabaseOnly, params string[] domainObjectNames)
        {
            if (domainObjectNames == null)
                return;
            if (this.DatabaseRelations == null)
                return;
            this.DatabaseRelations.RemoveItemsByDomainObjectNames(isDatabaseOnly, domainObjectNames);
            this.ManyRelations = null;
            this.ChildRelations = null;
            this.ParentRelations = null;
        }

        #endregion
        #region SetPropertyAsCultureItem

        public DomainObjectProperty SetPropertyAsCultureItem(string propertyName)
        {
            var item = GetProperty(propertyName);
            if (item != null)
                item.SetPropertyAsCultureItem();
            return item;
        }

        #endregion
        #region SetPropertyAsCustomType

        public DomainObjectProperty SetPropertyAsCustomType(string propertyName, string typeName, string defaultValue, bool? isNullable,
            string deserializeFormat, string stringFormat, string valueFormat, string valueFormatInDataStore)
        {
            var item = GetProperty(propertyName);
            if (item != null)
                item.SetPropertyAsCustomType(typeName, defaultValue, isNullable, deserializeFormat, stringFormat, valueFormat, valueFormatInDataStore);
            return item;
        }

        #endregion
        #region SetPropertyAsEnum

        public DomainObjectProperty SetPropertyAsEnum(string propertyName, string enumName, string defaultValue, bool? isNullable)
        {
            var item = GetProperty(propertyName);
            if (item != null)
                item.SetPropertyAsEnum(enumName, defaultValue, isNullable);
            return item;
        }

        #endregion
        #region SetPropertyValues

        public DomainObjectProperty SetPropertyValues(string propertyName, string defaultValue)
        {
            var item = GetProperty(propertyName);
            if (item != null)
                item.SetPropertyValues(defaultValue);
            return item;
        }
        public DomainObjectProperty SetPropertyValues(string propertyName, string defaultValue, int? maxLength, decimal? minValue, decimal? maxValue, byte? maxDecimalCount)
        {
            DomainObjectProperty item;

            item = GetProperty(propertyName);
            if (item != null)
                item.SetPropertyValues(defaultValue, maxLength, minValue, maxValue, maxDecimalCount);
            return item;
        }

        #endregion
        #region SetPropertyName

        public DomainObjectProperty SetPropertyName(string propertyName, string newPropertyName)
        {
            var item = GetProperty(propertyName);
            if (item != null)
                item.SetPropertyName(newPropertyName);
            return item;
        }

        #endregion
        #region ToString

        public override string ToString()
        {
            return this.FullName;
        }

        #endregion

        // static
        #region GetFullName

        public static string GetFullName(string @namespace, string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return string.Empty;
            if (string.IsNullOrWhiteSpace(@namespace))
                return name;
            return string.Join(".", @namespace, name);
        }

        #endregion

        #endregion
        #region Private Members

        #region AddIndexField

        private DomainObjectProperty AddIndexField(DomainObjectIndex index, string propertyName)
        {
            DomainObjectProperty item;

            item = GetProperty(propertyName);
            if (item != null)
                index.Fields.Add(item);

            return item;
        }

        #endregion
        #region PrepareRelationPaths

        private static System.Collections.Generic.List<DomainObjectRelationPath> PrepareRelationPaths(DomainObjectRelationPathCollection relationPaths, System.Collections.Generic.HashSet<string> names, DomainObject domainObject)
        {
            System.Collections.Generic.List<DomainObjectRelationPath> items;
            DomainObjectRelationPath item;

            items = new System.Collections.Generic.List<DomainObjectRelationPath>();
            foreach (var relation in domainObject.Relations)
            {
                if (names.Contains(relation.Name))
                    continue;
                names.Add(relation.Name);
                item = new DomainObjectRelationPath();
                item.DomainObjectRelations.Add(relation);
                relationPaths.Add(item);
                items.Add(item);
            }

            return items;
        }

        private static System.Collections.Generic.List<DomainObjectRelationPath> PrepareRelationPaths(DomainObjectRelationPathCollection relationPaths, System.Collections.Generic.HashSet<string> names, System.Collections.Generic.List<DomainObjectRelationPath> currentRelationPaths)
        {
            System.Collections.Generic.List<DomainObjectRelationPath> items;
            DomainObjectRelationPath item;

            items = new System.Collections.Generic.List<DomainObjectRelationPath>();
            foreach (var currentRelationPath in currentRelationPaths)
            {
                foreach (var relation in currentRelationPath.EndDomainObject.Relations)
                {
                    if (names.Contains(relation.Name))
                        continue;
                    names.Add(relation.Name);
                    item = currentRelationPath.Copy();
                    item.DomainObjectRelations.Add(relation);
                    relationPaths.Add(item);
                    items.Add(item);
                }
            }

            return items;
        }

        #endregion

        #endregion
        #region Constructors

        public DomainObject()
        {
            this.Properties = new DomainObjectPropertyCollection();
            this.Properties.SetDomainObject(this);
            this.DatabaseRelations = new DomainObjectRelationCollection();
            this.Indexes = new DomainObjectIndexCollection();
            this.HasSqliteDataLayer = true;
            this.HasUILayer = true;
            this.HasWebLayer = true;
            this.HasWebApiLayer = true;
            this.WebApiOperationTypes = OperationTypes.All;
        }

        #endregion
    }
}
